import sys, os
from PyQt4 import QtCore, QtGui, QtWebKit
from .moopsUI import Ui_MainWindow
from .consoleUI import Ui_ConsoleWindow
from .preferences import Ui_preferences
from ..emulator.cpu import cpu
from ..translator.translator import trans_file
from .style import Style
from ..libmoops import (TEXT_ADDRESS, DATA_ADDRESS, int_to_twos, twos_to_int)

 
class Moops(QtGui.QMainWindow):
    
    def __init__(self, parent=None):
        self.cpuExecution = False
        self.style = style.Style()
        self.style.setCleanLooks()
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        
        #self.ui.help.load(QtCore.QUrl.fromLocalFile("/home/matthew/moops/index.html"))
        self.ui.help.load(QtCore.QUrl(os.path.dirname(os.path.realpath(__file__)) + "/../help/index.html"))
        
        self.dialog = QtGui.QDialog()
        self.dialog.accept()
        self.cmd = Ui_ConsoleWindow()
        self.cmd.setupUi(self.dialog)
        self.dialog.show()
        

        #self.ui.mdiArea.addSubWindow(self.dialog)
        

        
        QtCore.QObject.connect(self.ui.runAsm, QtCore.SIGNAL("clicked()"), self.runAsm )
        QtCore.QObject.connect(self.ui.actionOpen_ASM, QtCore.SIGNAL("triggered()"), self.runAsm )
        QtCore.QObject.connect(self.ui.actionOpen_BIN, QtCore.SIGNAL("triggered()"), self.loadFile )
        QtCore.QObject.connect(self.ui.actionTranslate_ASM, QtCore.SIGNAL("triggered()"), self.translateAsm )
        QtCore.QObject.connect(self.ui.ExecuteBtn, QtCore.SIGNAL("clicked()"), self.execute_cpu )
        QtCore.QObject.connect(self.ui.InitializeBtn, QtCore.SIGNAL("clicked()"), self.initialize_pc )
        QtCore.QObject.connect(self.ui.StepBtn, QtCore.SIGNAL("clicked()"), self.cpu_step )
        #QtCore.QObject.connect(self.ui.AtmStepBtn, QtCore.SIGNAL("clicked()"), self.atmCpuStep )#actionCleanlooks
        
        QtCore.QObject.connect(self.ui.actionPreferences, QtCore.SIGNAL("triggered()"), self.preferences )
        
        QtCore.QObject.connect(self.ui.actionCleanlooks, QtCore.SIGNAL("triggered()"), self.style.setCleanLooks )
        QtCore.QObject.connect(self.ui.actionWindows, QtCore.SIGNAL("triggered()"), self.style.setWindows )
        QtCore.QObject.connect(self.ui.actionMotif, QtCore.SIGNAL("triggered()"), self.style.setMotif )
        QtCore.QObject.connect(self.ui.actionDefault, QtCore.SIGNAL("triggered()"), self.style.setDefault )
        QtCore.QObject.connect(self.ui.actionCDE, QtCore.SIGNAL("triggered()"), self.style.setCDE )
        
        ##Console
        self.cmd.enterCommand.setEnabled(False)
        QtCore.QObject.connect(self.cmd.enterCommand, QtCore.SIGNAL("clicked()"), self.syscallInput )
        
        
        ##create cpu
        self.cpu = cpu()
        

    def preferences(self):        
        ##preferences
        self.preferences = Ui_preferences()
        self.dialog = QtGui.QDialog()
        self.dialog.accept()
        self.preferences.setupUi(self.dialog)
        self.dialog.show()
        
        self.prefLoad()
        QtCore.QObject.connect(self.preferences.cancelBtn, QtCore.SIGNAL("clicked()"), self.prefQuit )
        QtCore.QObject.connect(self.preferences.okBtn, QtCore.SIGNAL("clicked()"), self.prefSaveQuit )
        QtCore.QObject.connect(self.preferences.applyBtn, QtCore.SIGNAL("clicked()"), self.prefSave )
        
    def prefQuit(self):
        self.dialog.close()
        
    def prefSave(self):
        self.cpu.pipeline = self.preferences.pipeline.checkState()
        self.cpu.hazardDetection = self.preferences.hazard.checkState()
        self.cpu.forwarding_unit = self.preferences.forward.checkState()
        self.cpu.exceptionFile = self.preferences.exceptionLocation.text()
        
    def prefSaveQuit(self):
        self.prefSave()
        self.prefQuit()
    
    def prefLoad(self):
        self.preferences.pipeline.setChecked(self.cpu.pipeline)
        self.preferences.hazard.setChecked(self.cpu.hazardDetection)
        self.preferences.forward.setChecked(self.cpu.forwarding_unit)
        self.preferences.exceptionLocation.setText(self.cpu.exceptionFile)

    def menuUpdate(self):
        print("lol")

    def displayGPRDock(self): #displays the general purpose register dock
        if (self.ui.actionGPRDock.isChecked()==True):
           self.ui.GPRDock.show()
        else:
           self.ui.GPRDock.hide()

    def systemCalls(self):
        #print("lolz" + chr(97))
        if (self.cpu.memwb.signalSyscall == 1): ##if there is a syscall
            print("in syscalls")
            rv0 = self.cpu.register.readRegister(2)
            print("rv0 " + str(rv0))
            if (rv0==1): #print int to terminal
                ra0 = self.cpu.register.readRegister(4)
                self.cmd.consoleOut.append( str(ra0) )
            elif (rv0==2): #print float to terminal
                self.cmd.consoleOut.append( "Print Float: FPU Not Implemented" )
            elif (rv0==3): #print double to terminal
                self.cmd.consoleOut.append( "Print Double: FPU Not Implemented" )
            elif (rv0==4): #Pring String, only supports little endian atm
                ra0 = self.cpu.register.readRegister(4)
                print(hex(ra0))
                count = 0
                NullTerminal=False
                while (NullTerminal == False): #data != '/'
                    data = self.cpu.getByte( ra0 + count) #0x00 / '/' represents when to stop
                    print("data " + hex(data))
                    if (data != 0x00):
                        self.cmd.consoleOut.insertPlainText( chr(data) )
                    else:
                        NullTerminal = True
                    count=count + 1
            elif (rv0==5 or rv0==8): #5 is to read int, 8 is to read string
                self.cmd.enterCommand.setEnabled(True)
                self.ui.StepBtn.setEnabled(False)
                self.ui.ExecuteBtn.setEnabled(False)
                self.cpuExecution = False
            elif (rv0 == 10):
                self.cpuExecution = False
            
                
    def syscallInput(self):
        if (self.cmd.lineEdit.text()!=''):
            rv0 = self.cpu.register.readRegister(2)
            if (rv0 == 5): #read int
                rv0 = int(self.cmd.lineEdit.text())
                self.cmd.consoleOut.append( str(rv0) )
                self.cpu.register.writeRegister(2,int_to_twos(rv0))
            #elif (rv0 == 8): ##read string
                #ra0 = self.cpu.register.readRegister(4)
                #ra1 = self.cpu.register.readRegister(5)
            self.cmd.enterCommand.setEnabled(False)
            self.ui.StepBtn.setEnabled(True)
            self.ui.ExecuteBtn.setEnabled(True)

    def runAsm(self):
        asmFile = str(QtGui.QFileDialog.getOpenFileName(self, 'Open file', ''))
        if(asmFile!=''):
            trans_file(str(asmFile))
        
        self.initialize_pc()
            
        elfFile = asmFile.split('.', 1)[0]+'.bin'
        if(elfFile!=''):
            self.cpu.loadBinary(elfFile)
            self.addInstructions()
            self.readData()

    def translateAsm(self):
        asmFile = QtGui.QFileDialog.getOpenFileName(self, 'Open file', '')
        if(asmFile!=''):
            trans_file(str(asmFile))

    def addInstructions(self):
        self.ui.InstructionMemory.clear()
        instructionCount = self.cpu.getInstructionCount()
        for i in range(instructionCount):
            instruction = "0x%08X" % self.cpu.getInstruction( int(TEXT_ADDRESS+i*4) )
            pc = "0x%08X" % int(TEXT_ADDRESS+i*4)
            self.currentInstruction = QtGui.QListWidgetItem( pc + " " + instruction )
            self.ui.InstructionMemory.insertItem(i, self.currentInstruction)

    def readData(self):
        self.ui.kuserMemory.clear()
        self.ui.kseg0Memory.clear()
        self.ui.kseg1Memory.clear()
        self.ui.kseg2Memory.clear()
        
        count = 0
        for i in sorted(self.cpu.memory.kuser.keys()):
            self.ui.kuserMemory.insertItem(count, "0x%08X" %i + " " + "0x%08X" %self.cpu.memory.kuser[i])
            count = count + 1
            
        count = 0
        for i in sorted(self.cpu.memory.kseg0.keys()):
            self.ui.kseg0Memory.insertItem(count, "0x%08X" %i + " " + "0x%08X" %self.cpu.memory.kseg0[i])
            count = count + 1
            
        count = 0
        for i in sorted(self.cpu.memory.kseg1.keys()):
            self.ui.kseg1Memory.insertItem(count, "0x%08X" %i + " " + "0x%08X" %self.cpu.memory.kseg1[i])
            count = count + 1
            
            count = 0
        for i in sorted(self.cpu.memory.kseg2.keys()):
            self.ui.kseg2Memory.insertItem(count, "0x%08X" %i + " " + "0x%08X" %self.cpu.memory.kseg2[i])
            count = count + 1


    def loadFile(self):
        elfFile = QtGui.QFileDialog.getOpenFileName(self, 'Open file', '')
        if(elfFile!=''):
            self.cpu.loadBinary(elfFile)
            self.addInstructions()
            self.readData()

    def display_registers(self):
        self.registerState = self.cpu.getRegisterState()
        k=0
        for i in range(6):
            for j in range(6):
                if (k>31):
                    break
                register = "$r" + str("%02d")%k
                value = "0x%08X" % int(self.registerState[k]) #"0x" + repr(hex(int(self.registerState[k]))[2:].zfill(8).upper())
                self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
                self.ui.registerStatus.setItem(i, j, self.currentRegister)
                k = k+1
        register = "hi:"
        value = "0x%08X" % int(self.cpu.hilo[0])
        self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
        self.ui.registerStatus.setItem(5, 4, self.currentRegister)
        
        register = "lo:"
        value = "0x%08X" % int(self.cpu.hilo[1])
        self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
        self.ui.registerStatus.setItem(5, 5, self.currentRegister)
        
        register = "Status:"
        value = "0x%08X" % int(self.cpu.cp0.register.readRegister(12))
        self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
        self.ui.cp0RegStatus.setItem(2, 0, self.currentRegister)
        
        register = "Cause:"
        value = "0x%08X" % int(self.cpu.cp0.register.readRegister(13))
        self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
        self.ui.cp0RegStatus.setItem(2, 1, self.currentRegister)
        
        register = "EPC:"
        value = "0x%08X" % int(self.cpu.cp0.register.readRegister(14))
        self.currentRegister = QtGui.QTableWidgetItem( register + " " + value)
        self.ui.cp0RegStatus.setItem(2, 2, self.currentRegister)

    def initialize_pc(self):
        self.ui.InstructionMemory.clear()
        self.ui.kuserMemory.clear()
        self.cpu.initializePipeline()
        self.display_registers()

    def executing_instruction(self):
        instruction = self.cpu.getInstruction(self.pc)
        self.ui.executingInstruction.setText(hex(self.pc) + ' ' + hex(instruction))

    def execute_cpu(self):
        self.cpuExecution = True
        while (self.cpuExecution):
            if (self.cpu.memory.exist(self.cpu.pc) == False):
                self.cpuExecution = False
                #use for quit#reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure to quit?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
                QtGui.QMessageBox.question(self, 'Message', "Memory uninitialized at " + hex(self.cpu.pc))
            self.cpu_step()


    def cpu_step(self):
        self.pc = self.cpu.getPc()
        pcstep = (self.pc & 0x000FFFFF)/4
        self.executing_instruction()
        if(self.ui.InstructionMemory.item(pcstep)):
            self.ui.InstructionMemory.item(pcstep).setSelected(True)
        else:
            self.ui.InstructionMemory.clearSelection()
        self.cpu.step()
        self.display_registers()
        self.readData()
        self.systemCalls()



def run():
    app = QtGui.QApplication(sys.argv)
    myapp = Moops()
    myapp.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    run()
